#include "inputbox.hpp"

void InitInputMenu(Window* w){
    w->_input_list=new MenuList(1,new vector<MenuItem*>{
        new InputItem(w,"复制"),new InputItem(w,"黏贴"),
        new InputItem(w,"剪切"),new InputItem(w,"全选")
    });
}

InputBox::BaseDo::~BaseDo(){delete text;}

InputBox::DoAdd::DoAdd(string* t,vector<U8Unit>* u,size_t tb,size_t ub){
    text=t,tbegin=tb,ubegin=ub;
    units=*u;
}
void InputBox::DoAdd::UnDo(InputBox* p){
    p->_begin_text=_tbegin,p->_end_text=_tend,p->_begin_unit=_ubegin,p->_end_unit=_uend;
    auto _t=p->_text;
    auto _u=p->_units;
    auto tb=_t->begin()+tbegin;
    auto ub=_u->begin()+ubegin;
    _t->erase(tb,tb+text->size());
    _u->erase(ub,ub+units.size());
    p->_cur_unit=ubegin;
    p->_cur_text=tbegin;
}
void InputBox::DoAdd::ReDo(InputBox* p){
    p->_begin_text=_tbegin,p->_end_text=_tend,p->_begin_unit=_ubegin,p->_end_unit=_uend;
    auto _t=p->_text;
    auto _u=p->_units;
    _t->insert(_t->begin()+tbegin,text->begin(),text->end());
    _u->insert(_u->begin()+ubegin,units.begin(),units.end());
    p->_cur_unit=ubegin+units.size();
    p->_cur_text=tbegin+text->size();
}

InputBox::DoRemove::DoRemove(string* t,vector<U8Unit>::iterator begin,vector<U8Unit>::iterator end,
size_t tb,size_t ub,size_t _tb,size_t _te,size_t _ub,size_t _ue){
    text=t,tbegin=tb,ubegin=ub;
    units.insert(units.end(),begin,end);
    _tbegin=_tb,_tend=_te,_ubegin=_ub,_uend=_ue;
}
void InputBox::DoRemove::UnDo(InputBox* p){
    p->_begin_text=_tbegin,p->_end_text=_tend,p->_begin_unit=_ubegin,p->_end_unit=_uend;
    auto _t=p->_text;
    auto _u=p->_units;
    _t->insert(_t->begin()+tbegin,text->begin(),text->end());
    _u->insert(_u->begin()+ubegin,units.begin(),units.end());
    p->_cur_unit=ubegin+units.size();
    p->_cur_text=tbegin+text->size();
}
void InputBox::DoRemove::ReDo(InputBox* p){
    p->_begin_text=_tbegin,p->_end_text=_tend,p->_begin_unit=_ubegin,p->_end_unit=_uend;
    auto _t=p->_text;
    auto _u=p->_units;
    auto tb=_t->begin()+tbegin;
    auto ub=_u->begin()+ubegin;
    _t->erase(tb,tb+text->size());
    _u->erase(ub,ub+units.size());
    p->_cur_unit=ubegin;
    p->_cur_text=tbegin;
}

InputBox::DoReplace::DoReplace(string* t,vector<U8Unit>* u,string* t2,vector<U8Unit>::iterator begin,vector<U8Unit>::iterator end,
size_t tb,size_t ub,size_t _tb,size_t _te,size_t _ub,size_t _ue){
    text=t;
    units=*u;
    units2.insert(units2.end(),begin,end);
    text2=t2;
    tbegin=tb,ubegin=ub;
    this->_ub=_ub;
    this->_ue=_ue;
    this->_tb=_tb;
    this->_te=_te;
}
void InputBox::DoReplace::UnDo(InputBox* p){
    p->_begin_text=_tb,p->_end_text=_te,p->_begin_unit=_ub,p->_end_unit=_ue;
    auto _t=p->_text;
    auto _u=p->_units;
    auto tb=_t->begin()+tbegin;
    auto ub=_u->begin()+ubegin;
    _t->erase(tb,tb+text->length());
    _u->erase(ub,ub+units.size());
    _t->insert(_t->begin()+tbegin,text2->begin(),text2->end());
    _u->insert(_u->begin()+ubegin,units2.begin(),units2.end());
    p->_cur_unit=ubegin+units2.size();
    p->_cur_text=tbegin+text2->length();
}
void InputBox::DoReplace::ReDo(InputBox* p){
    p->_begin_text=_tbegin,p->_end_text=_tend,p->_begin_unit=_ubegin,p->_end_unit=_uend;
    auto _t=p->_text;
    auto _u=p->_units;
    auto tb=_t->begin()+tbegin;
    auto ub=_u->begin()+ubegin;
    _t->erase(tb,tb+text2->size());
    _u->erase(ub,ub+units2.size());
    _t->insert(_t->begin()+tbegin,text->begin(),text->end());
    _u->insert(_u->begin()+ubegin,units.begin(),units.end());
    p->_cur_unit=ubegin+units.size();
    p->_cur_text=tbegin+text->size();
}
InputBox::DoReplace::~DoReplace(){delete text2;}

void InputBox::ListenMouse(void* i){
    auto &r=((InputBox*)i)->_area;
    int x,y;
    SDL_GetMouseState(&x,&y);
    auto _u=((InputBox*)i)->_units;
    if(((InputBox*)i)->pressed&&!_u->empty()){
        if(x<=r.x){
            if(((InputBox*)i)->_begin_text){
                ((InputBox*)i)->_begin_text-=(_u->begin()+--((InputBox*)i)->_begin_unit)->len;
                ((InputBox*)i)->_end_text-=(_u->begin()+--((InputBox*)i)->_end_unit)->len;
            }
            ((InputBox*)i)->_s_tbegin=((InputBox*)i)->_begin_text;
            ((InputBox*)i)->_s_ubegin=((InputBox*)i)->_begin_unit;
            ((InputBox*)i)->_cur_text=((InputBox*)i)->_begin_text;
            ((InputBox*)i)->_cur_unit=((InputBox*)i)->_begin_unit;
            return;
        }
        if(x>=r.x+r.w){
            if(((InputBox*)i)->_end_unit<_u->size()){
                ((InputBox*)i)->_begin_text+=(_u->begin()+ ((InputBox*)i)->_begin_unit++)->len;
                ((InputBox*)i)->_end_text+=(_u->begin()+ ((InputBox*)i)->_end_unit++)->len;
            }
            ((InputBox*)i)->_s_tend=((InputBox*)i)->_end_text;
            ((InputBox*)i)->_s_uend=((InputBox*)i)->_end_unit;
            ((InputBox*)i)->_cur_unit=((InputBox*)i)->_end_unit;
            ((InputBox*)i)->_cur_text=((InputBox*)i)->_end_text;
            return;
        }
        //选左+1
        int max=x-r.x;
        int c=0;
        auto s=((InputBox*)i)->_begin_text;
        auto ubegin=_u->begin()+((InputBox*)i)->_begin_unit,uend=_u->begin()+((InputBox*)i)->_end_unit;
        if(x<((InputBox*)i)->_x){
            while(ubegin!=uend){
                auto &u=*ubegin;
                c+=u.w;
                if(c>=max){
                    ((InputBox*)i)->_s_tbegin=s;
                    ((InputBox*)i)->_s_ubegin=ubegin-_u->begin();
                    ((InputBox*)i)->_cur_unit=((InputBox*)i)->_s_ubegin;
                    ((InputBox*)i)->_cur_text=((InputBox*)i)->_s_tbegin;
                    return;
                }
                s+=u.len;
                ubegin++;
            }
            ((InputBox*)i)->_s_tbegin=((InputBox*)i)->_begin_text;
            ((InputBox*)i)->_s_ubegin=((InputBox*)i)->_begin_unit;
            ((InputBox*)i)->_cur_unit=((InputBox*)i)->_s_ubegin;
            ((InputBox*)i)->_cur_text=((InputBox*)i)->_s_tbegin;
            return;
        }
        if(x>((InputBox*)i)->_x){
            while(ubegin!=uend){
                auto &u=*ubegin;
                c+=u.w;
                if(c>=max){
                    ((InputBox*)i)->_s_tend=s;
                    ((InputBox*)i)->_s_uend=ubegin-_u->begin();
                    ((InputBox*)i)->_cur_unit=((InputBox*)i)->_s_uend;
                    ((InputBox*)i)->_cur_text=((InputBox*)i)->_s_tend;
                    return;
                }
                s+=u.len;
                ubegin++;
            }
            ((InputBox*)i)->_s_tend=((InputBox*)i)->_end_text;
            ((InputBox*)i)->_s_uend=((InputBox*)i)->_end_unit;
            ((InputBox*)i)->_cur_unit=((InputBox*)i)->_s_uend;
            ((InputBox*)i)->_cur_text=((InputBox*)i)->_s_tend;
            return;
        }
    }
    if(x<r.x||x>r.x+r.w||y<r.y||y>r.y+r.h){
        ((InputBox*)i)->_belong->RemoveTask(((InputBox*)i)->_task);
        ((InputBox*)i)->_task=NULL;
        SDL_SetCursor(arrow_cursor);
    }
}
void InputBox::_cut(){
    if(!_s_uend){
        return;
    }
    _begin_do();
    auto _u=_units;
    auto _t=_text;
    auto dt=_s_tend-_s_tbegin,du=_s_uend-_s_ubegin;
    auto bt=_begin_text,bu=_begin_unit;
    auto ubegin=_u->begin()+_s_ubegin,uend=ubegin+du;
    auto tbegin=_t->begin()+_s_tbegin,tend=tbegin+dt;
    _cur_unit=_s_ubegin;
    _cur_text=_s_tbegin;
    if(du>bu){
        _begin_unit=0,_begin_text=0;
    }
    else{
        _begin_unit-=du,_begin_text-=dt;
    }
    _end_text-=dt;
    _end_unit-=du;
    if(_max_do){
        undo->push_front(new DoRemove(new string(tbegin,tbegin+dt),ubegin,ubegin+du,_cur_text,
        _cur_unit,_begin_text,_end_text,_begin_unit,_end_unit));
    }
    _u->erase(ubegin,uend);
    _t->erase(tbegin,tend);
    _s_tbegin=0;
    _s_tend=0;
    _s_ubegin=0;
    _s_uend=0;
    OnTextChanged();
}

void InputBox::_begin_do(){
    for(auto item=redo->begin(),end=redo->end();item!=end;item++){
        delete *item;
    }
    if(_max_do){
        if(++_cur_do>_max_do){
            --_cur_do;
            delete undo->back();
            undo->pop_back();
        }
    }
    redo->clear();
}
void InputBox::_process_outside(BaseDo* temp){
    _end_unit=_cur_unit;
    _end_text=_cur_text;
    auto begin=_units->begin();
    auto cur=_units->begin()+_end_unit;
    auto _s=_end_text;
    int w=10;
    int m=_area.w;
    for(;;){
        if(begin==cur){
            if(temp){
                undo->push_front(temp);
            }
            OnTextChanged();
            return;
        }
        auto &u=*(--cur);
        w+=u.w;
        if(w>=m){
            _begin_text=_s;
            _begin_unit=cur-_units->begin()+1;
            if(temp){
                temp->_tbegin=_begin_text;
                temp->_tend=_end_text;
                temp->_ubegin=_begin_unit;
                temp->_uend=_end_unit;
                undo->push_front(temp);
            }
            OnTextChanged();
            return;
        }
        _s-=u.len;
    }
}

void InputBox::_copy(){
    SDL_SetClipboardText(_text->substr(_s_tbegin,_s_tend-_s_tbegin).c_str());
}

void InputBox::_paste(){
    auto s=SDL_GetClipboardText();
    _input(s);
    SDL_free(s);
}

void InputBox::_select_all(){
    _s_tbegin=0,_s_tend=_text->length();
    _s_ubegin=0,_s_uend=_units->size();
}

const string* InputBox::text(){return _text;}
SDL_Color InputBox::text_color(){return this->_text_color;}
Font* InputBox::font(){return this->_font;}

InputBox::InputBox(Window* window,SDL_Rect& rect,SDL_Color background,Font* font,const char* alert,
const char* init_text,SDL_Color _text_color,SDL_Color select_color,SDL_Color line_color,
SDL_Color disable_color,SDL_Color cursor_color,unsigned int max_do):Control(window){
    _task=NULL;
    _area=rect;
    this->background=background;
    this->_font=font;
    auto r=window->renderer;
    _alert=r->RenderText(font,alert,_text_color);
    SDL_SetTextureAlphaMod(_alert,150);
    _begin_unit=0,_begin_text=0,_end_unit=0,_end_text=0,_cur_text=0,_cur_unit=0;
    _max_do=max_do;
    _cur_do=0;
    _s_tbegin=0,_s_tend=0,_s_ubegin=0,_s_uend=0;
    redo=new list<BaseDo*>();
    undo=new list<BaseDo*>();
    _units=new vector<U8Unit>();
    _text=new string();
    this->line_color=line_color;
    this->select_color=select_color;
    this->_text_color=_text_color;
    this->cursor_color=cursor_color;
    _t=r->CreateTexture(rect.w-5,rect.h);
    _input_start=false;
    _input(init_text);
}
InputBox::InputBox(Window* window):Control(window){
    _task=NULL;
    _cur_do=0;
    _s_tbegin=0,_s_tend=0,_s_ubegin=0,_s_uend=0;
    cursor_color=Color::Red;
    _flash_count=0;
    _flash=false;
    background=Color::White;
    _units=new vector<U8Unit>();
    line_color=Color::Black;
    select_color=Color::SkyBlueGray;
    disable_color=Color::Gray;
    _text_color=Color::Black;
    _text=new string();
    _font=default_font;
    auto r=window->renderer;
    _alert=r->RenderText(default_font,"input..",Color::Black);
    SDL_SetTextureAlphaMod(_alert,150);
    _t=r->CreateTexture(0,0);
    _input_start=false;
    _begin_unit=0,_begin_text=0,_end_unit=0,_end_text=0,_cur_text=0,_cur_unit=0;
    _max_do=64;
    redo=new list<BaseDo*>();
    undo=new list<BaseDo*>();
}
void InputBox::SetSize(int w,int h){
    _area.w=w,_area.h=h;
    SDL_DestroyTexture(_t);
    _t=_belong->renderer->CreateTexture(w-5,_font->height());
}
InputBox::~InputBox(){
    delete _units;
    if(_alert){
        SDL_DestroyTexture(_alert);
    }
    SDL_DestroyTexture(_t);
    delete _text;
    for(auto item=redo->begin(),end=redo->end();item!=end;item++){
        delete *item;
    }
    delete redo;
    for(auto item=undo->begin(),end=undo->end();item!=end;item++){
        delete *item;
    }
    delete undo;
    if(_task){
        _belong->RemoveTask(_task);
    }
}
//可NULL
void InputBox::SetAlert(const char* new_alert){
    if(!new_alert){
        if(_alert){
            SDL_DestroyTexture(_alert);
            _alert=NULL;
            return;
        }
    }
    if(_alert){
        SDL_DestroyTexture(_alert);
    }
    _alert=_belong->renderer->RenderText(_font,new_alert,line_color);
    SDL_SetTextureAlphaMod(_alert,150);
}
void InputBox::SetText(const char* new_text,SDL_Color _text_color,SDL_Color select_color){
    this->_text_color=_text_color;
    this->select_color=select_color;
    _text->clear();
    _units->clear();
    _cur_text=0,_cur_unit=0,_begin_unit=0,_end_unit=0,_begin_text=0,_end_text=0;
    _s_tbegin=0,_s_tend=0,_s_ubegin=0,_s_uend=0;
    _input(new_text);
}

void InputBox::_mouse_move(int x,int y){
    if(!_task&&_enabled){
        SDL_SetCursor(edit_cursor);
        _task=_belong->AddTask(ListenMouse,this,1,false,true);
    }
}
void InputBox::_draw(){
    auto r=_belong->renderer;
    SDL_Rect rect{_area.x,_area.y};
    if(!_enabled){
        SDL_SetTextureAlphaMod(_t,150);
        auto s=_text->data();
        r->RenderHorizontalText(_t,disable_color,_font,s+_begin_text,s+_text->length(),_text_color);
        SDL_QueryTexture(_t,NULL,NULL,&rect.w,&rect.h);
        r->DrawTexture(NULL,&rect,_t);
        r->SetColor(line_color);
        r->DrawRect(_area);
        return;
    }
    if(_text->empty()&&_alert){
        r->SetColor(background);
        r->FillRect(_area);
        r->SetColor(line_color);
        r->DrawRect(_area);
        SDL_QueryTexture(_alert,NULL,NULL,&rect.w,&rect.h);
        rect.w=min(rect.w,_area.w);
        r->DrawTexture(NULL,&rect,_alert);
        if(++_flash_count==_input_delay){
            _flash_count=0;
            _flash=!_flash;
        }
        if(_input_start&&_flash){
            r->SetColor(cursor_color);
            int temp=0;
            auto cur=_units->begin()+_cur_unit;
            for(auto begin=_units->begin()+_begin_unit,end=_units->end();begin!=end;begin++){
                if(begin==cur){
                    break;
                }
                temp+=begin->w;
            }
            rect.x+=temp;
            rect.w=2;
            r->FillRect(rect);
        }
        return;
    }
    SDL_SetTextureAlphaMod(_t,255);
    auto s=_text->data();
    r->RenderHighlightHorizontalText(_t,background,_font,s+_begin_text,s+_text->size(),_text_color,s+_s_tbegin,s+_s_tend,select_color);
    SDL_QueryTexture(_t,NULL,NULL,&rect.w,&rect.h);
    r->DrawTexture(NULL,&rect,_t);
    r->SetColor(line_color);
    r->DrawRect(_area);
    if(++_flash_count==_input_delay){
        _flash_count=0;
        _flash=!_flash;
    }
    if(_input_start&&_flash){
        r->SetColor(cursor_color);
        int temp=0;
        auto cur=_units->begin()+_cur_unit;
        for(auto begin=_units->begin()+_begin_unit,end=_units->end();begin!=end;begin++){
            if(begin==cur){
                break;
            }
            temp+=begin->w;
        }
        rect.x+=temp;
        rect.w=2;
        r->FillRect(rect);
    }
}
//空时不会进行任何操作
void InputBox::_input(const char* text){
    string s(text);
    if(s.empty()){
        return;
    }
    _begin_do();
    auto _t=_text;
    auto _u=_units;
    auto cur_unit=_cur_unit;
    auto size=_t->length();
    auto l=_belong->renderer->SaveU8Units(text,_font,_text_color);
    auto _ubegin=l->begin(),_uend=l->end();
    BaseDo* temp=NULL;
    if(_s_uend){
        auto ubegin=_s_ubegin,tbegin=_s_tbegin,uend=_s_uend,tend=_s_tend;
        if(_max_do){
            temp=new DoReplace(new string(s),l,new string(_t->begin()+tbegin,_t->begin()+tend),
            _u->begin()+ubegin,_u->begin()+uend,tbegin,ubegin,_begin_text,_end_text,_begin_unit,_end_unit);
        }
        _t->erase(_t->begin()+tbegin,_t->begin()+tend);
        _t->insert(_t->begin()+tbegin,s.begin(),s.end());
        _u->erase(_u->begin()+ubegin,_u->begin()+uend);
        _u->insert(_u->begin()+ubegin,_ubegin,_uend);
        _cur_unit=ubegin+l->size();
        _cur_text=tbegin+s.length();
        _s_tbegin=0;
        _s_tend=0;
        _s_ubegin=0;
        _s_uend=0;
    }
    else{
        _t->insert(_t->begin()+_cur_text,s.begin(),s.end());
        _u->insert(_u->begin()+cur_unit,_ubegin,_uend);
        if(_max_do){
            temp=new DoAdd(new string(s),l,_cur_text,cur_unit);
        }
        _cur_text+=s.size();
        _cur_unit+=l->size();
    }
    int w=5,m=_area.w;
    auto begin=_begin_unit+_u->begin(),end=_u->end();
    while(begin!=end){
        w+=begin->w;
        if(w>=m){
            //cur在end外
            _process_outside(temp);
            delete l;
            return;
        }
        begin++;
    }
    if(!_end_unit){
        _end_unit=_cur_unit;
        _end_text=_cur_text;
        _process_outside(temp);
        delete l;
        return;
    }
    if(_end_unit<_cur_unit){
        _process_outside(temp);
        delete l;
        return;
    }
    if(temp){
        temp->_tbegin=_begin_text;
        temp->_tend=_end_text;
        temp->_ubegin=_begin_unit;
        temp->_uend=_end_unit;
        undo->push_front(temp);
    }
    delete l;
    OnTextChanged();
}
void InputBox::_key_down(SDL_Keysym& sym){
    _flash=false;
    _flash_count=_input_delay-1;
    auto mod=sym.mod;
    switch(sym.sym){
        case SDLK_KP_ENTER:
        case SDLK_RETURN:
        case SDLK_RETURN2:
        _belong->CancelFocus(this);
        return;
        case SDLK_c:
        if(_cur_do&&(mod==KMOD_LCTRL||mod==KMOD_RCTRL)){
            _copy();
        }
        return;
        case SDLK_z:
        if(_cur_do&&(mod==KMOD_LCTRL||mod==KMOD_RCTRL)){
            _s_tbegin=0;
            _s_tend=0;
            _s_ubegin=0;
            _s_uend=0;
            _cur_do--;
            auto d=undo->front();
            undo->pop_front();
            redo->push_front(d);
            d->UnDo(this);
            OnTextChanged();
        }
        return;
        case SDLK_y:
        if(!redo->empty()&&(mod==KMOD_LCTRL||mod==KMOD_RCTRL)){
            _s_tbegin=0;
            _s_tend=0;
            _s_ubegin=0;
            _s_uend=0;
            _cur_do++;
            auto d=redo->front();
            redo->pop_front();
            undo->push_front(d);
            d->ReDo(this);
            OnTextChanged();
        }
        return;
        case SDLK_x:
        if(mod==KMOD_LCTRL||mod==KMOD_RCTRL){
            Cut(this);
        }
        return;
        case SDLK_v:
        if(mod==KMOD_LCTRL||mod==KMOD_RCTRL){
            _paste();
        }
        return;
        case SDLK_a:
        if(mod==KMOD_LCTRL||mod==KMOD_RCTRL){
            _select_all();
        }
        return;
        case SDLK_BACKSPACE:
        {
            auto _t=_text;
            if(_t->empty()){
                return;
            }
            if(_s_ubegin+_s_uend){
                _cut();
                return;
            }
            if(!_cur_unit)return;
            _begin_do();
            auto _u=_units;
            auto _back=_u->begin()+--_cur_unit;
            auto &back=*_back;
            auto begin=_t->begin()+_cur_text;
            auto len=back.len;
            _cur_text-=len;
            if(_max_do){
                undo->push_front(new DoRemove(new string(_t->data()+_cur_text,len),
                _back,_back+1,_cur_text,_cur_unit,_begin_text,_end_text,_begin_unit,_end_unit));
            }
            _t->erase(begin-len,begin);
            _u->erase(_back);
            _end_text-=len;
            _end_unit--;
            auto bu=_begin_unit;
            if(bu){
                _begin_unit--;
                _begin_text-=(_u->begin()+--bu)->len;
            }
            OnTextChanged();
        }
        return;
        case SDLK_LEFT:
        {
            auto cur=_cur_unit;
            if(!cur){
                return;
            }
            _s_tbegin=0;
            _s_tend=0;
            _s_ubegin=0;
            _s_uend=0;
            auto &back=*(_units->begin()+cur-1);
            auto len=back.len;
            _cur_text-=len;
            if(cur==_begin_unit){
                _begin_unit--;
                _begin_text-=len;
                _end_unit--;
                _end_text-=len;
            }
            _cur_unit--;
        }
        return;
        case SDLK_RIGHT:
        {
            auto cur=_cur_unit;
            if(cur==_units->size()){
                return;
            }
            _s_tbegin=0;
            _s_tend=0;
            _s_ubegin=0;
            _s_uend=0;
            auto back=*(_units->begin()+cur);
            auto len=back.len;
            _cur_text+=len;
            if(cur==_end_unit){
                _begin_unit++;
                _begin_text+=len;
                _end_unit++;
                _end_text+=len;
            }
            _cur_unit++;
        }
        return;
    }
}
void InputBox::_press(int x,int y,int clicks,unsigned char key){
    if(!_enabled){
        return;
    }
    if(key==SDL_BUTTON_RIGHT){
        pressed=false;
        return;
    }
    _x=x;
    int max=x-_area.x;
    int c=0;
    auto s=_begin_text;
    auto _u=_units;
    auto ubegin=_u->begin()+_begin_unit,uend=_u->begin()+_end_unit;
    while(ubegin!=uend){
        auto &u=*ubegin;
        c+=u.w;
        if(c>=max){
            _s_ubegin=ubegin-_u->begin();
            _s_tbegin=s;
            _s_uend=_s_ubegin;
            _s_tend=_s_tbegin;
            return;
        }
        s+=u.len;
        ubegin++;
    }
    _s_ubegin=_end_unit;
    _s_tbegin=_end_text;
    _s_uend=_s_ubegin;
    _s_tend=_s_tbegin;
}

void InputBox::OnFocus(){
    SDL_StartTextInput();
    _input_start=true;
}
void InputBox::LoseFocus(){
    SDL_StopTextInput();
    _input_start=false;
    OnInputFinish();
}
void InputBox::Cut(InputBox* i){
    if(!i->_s_uend){
        return;
    }
    i->_copy();
    i->_cut();
}
void InputBox::Copy(InputBox* i){
    i->_copy();
}
void InputBox::Paste(InputBox* i){
    i->_paste();
}
void InputBox::SelectAll(InputBox* i){
    i->_select_all();
}

static void(*_basic_input_menu[4])(MenuItem*){InputItem::Copy,InputItem::Paste,InputItem::Cut,InputItem::SelectAll};

void InputBox::_release(int x,int y,int clicks,unsigned char key){
    if(!_enabled){
        return;
    }
    _flash=false;
    _flash_count=_input_delay-1;
    if(key==SDL_BUTTON_RIGHT){
        auto a=_belong->_input_list;
        _belong->ActiveMenu(a);
        auto begin=a->children->begin();
        for(auto item=begin,end=a->children->end();item!=end;item++){
            auto c=(InputItem*)*item;
            c->box=this;
            c->func=_basic_input_menu[item-begin];
        }
        a->_rect={x,y,a->_w,(int)a->children->size()*_menu_item_height};
        return;
    }
    int max=x-_area.x;
    int c=0;
    auto s=_begin_text;
    auto _u=_units;
    auto ubegin=_u->begin()+_begin_unit,uend=_u->begin()+_end_unit;
    while(ubegin!=uend){
        auto &u=*ubegin;
        c+=u.w,s+=u.len;
        if(c>=max){
            _cur_unit=ubegin-_u->begin();
            _cur_text=s;
            return;
        }
        ubegin++;
    }
    _cur_unit=_end_unit;
    _cur_text=_end_text;
}

void InputItem::Copy(MenuItem* i){
    auto b=((InputItem*)i)->box;
    b->Copy(b);
}
void InputItem::Cut(MenuItem* i){
    auto b=((InputItem*)i)->box;
    b->Cut(b);
}
void InputItem::Paste(MenuItem* i){
    auto b=((InputItem*)i)->box;
    b->Paste(b);
}
void InputItem::SelectAll(MenuItem* i){
    auto b=((InputItem*)i)->box;
    b->SelectAll(b);
}
InputItem::InputItem(Window* w,const char* t):MenuText(w,t){}
InputItem::~InputItem(){}
bool InputItem::DrawCheck(){return false;}